﻿using AspNetCore.Host.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace AspNetCore.Host.Hosting
{
    public class WebApplication : IApplicationBuilder, IEndpointRouteBuilder
    {
        public IServiceProvider Services { get; }
        public ILogger Logger { get; }
        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }

        public IFeatureCollection ServerFeatures { get; }

        public EndpointDataSource? EndpointDataSource => ServerFeatures.Get<EndpointDataSource>();

        private IApplicationBuilder _application;

        public static WebApplicationBuilder CreateBuilder()
        {
            var configuration = new ConfigurationManager();
            configuration.AddEnvironmentVariables("ASPNETCORE_");
            var environmentName = configuration.GetValue<string>("Environment");
            var environment = new WebHostEnvironment(environmentName);
            configuration.AddJsonFile("appsettings.json", true, true);
            configuration.AddJsonFile($"appsettings.{environmentName}.json", true, true);
            return new WebApplicationBuilder(
                environment,
                configuration);
        }

        public WebApplication(IServiceProvider serviceProvider)
        {
            _application = new ApplicationBuilder();
            Services = serviceProvider;
            ServerFeatures = serviceProvider.GetRequiredService<IFeatureCollection>();
            Configuration = serviceProvider.GetRequiredService<IConfiguration>();
            Logger = serviceProvider.GetRequiredService<ILogger<WebApplication>>();
            Environment = serviceProvider.GetRequiredService<IWebHostEnvironment>();
        }

        public void Run()
        {
            var task = new TaskCompletionSource();
            var kestrel = ActivatorUtilities.CreateInstance<Kestrel>(Services);
            kestrel.Run(_application);
            task.Task.Wait();
        }

        public void Use(Func<RequestDelegate, RequestDelegate> middleware)
        {
            _application.Use(middleware);
        }


        public void Map(string pathMatch, RequestDelegate requst)
        {
            var dataSource = ServerFeatures.Get<EndpointDataSource>();
            var endpoint = new Endpoint(requst);
            endpoint.Metadata.Add(new HttpMethodAttribute(pathMatch));
            dataSource?.SetEndpoint(endpoint);
        }
    }
}
